package facade;

import java.util.*;

import usuarios.*;
import aerolineas.*;
import asientos.Asiento;
import asientos.Vuelo;
import busquedas.CriteriosBusqueda;
import busquedas.Orden;
import reservas.*;

/* Este es el punto de entrada al sistema, es un facade singleton. */
public class AterrizarPuntoCom {
	private static final AterrizarPuntoCom INSTANCE = new AterrizarPuntoCom();
	
	private Aerolineas aerolineas = new Aerolineas();
	private AdministradorDePerfiles administradorDeUsuarios = new AdministradorDePerfiles();
	private AdministradorDeReservas reservas = new AdministradorDeReservas();
	
	private static int recargo = 20;
	
	/* *************
	 * CONSTRUCCI�N
	 * ***********/
	private AterrizarPuntoCom() {
	}
	
	// Esta es la forma estandar de pedir instancias
	public static AterrizarPuntoCom getInstance() {
		return INSTANCE;
	}
	
	// Pero confiamos en el cliente y proveemos en al API otra forma, que devuelve una instancia nueva (no singleton), s�lo para testing.
	public static AterrizarPuntoCom nuevaInstanciaUsarSoloParaTesting() {
		return new AterrizarPuntoCom();
	}
	
	public List<Vuelo> unUsuarioBuscaPasajes(CriteriosBusqueda criterios, Usuario unUsuario, Orden unOrden) {
		List<Vuelo> asientos = this.aerolineas.buscarAsientos(criterios);
			
		List<Vuelo> asientosFiltrados=this.filtrarAsientos(asientos, unUsuario);
		unOrden.ordenar(asientosFiltrados);
		
		// guardo la busqueda al final, recien cuando se que anduvo todo bien
		// el administrador de usuarios, crea al perfil en la primer b�squeda
		// en el futuro, se supone que los usuarios estar�n pre creados, levantados de una base de datos o alg�n otro lado
		administradorDeUsuarios.GuardarBusqueda(unUsuario, criterios);
		
		return this.asientosConRecargo(asientosFiltrados, unUsuario, recargo);
	}

	private List<Vuelo> asientosConRecargo(List<Vuelo> asientos,
			Usuario unUsuario, int unRecargo) {
		for(Vuelo unAsiento : asientos) {
			unAsiento.recargarSegunUsuario(unUsuario, unRecargo);
		}
		return asientos;
	}

		
	private List<Vuelo> filtrarAsientos(List<Vuelo> asientos,
			Usuario unUsuario) {
		List<Vuelo> asientosFiltrados = new ArrayList<Vuelo>();
		
		for(Vuelo unAsiento : asientos) {
			if(unUsuario.debeVer(unAsiento)) {
				asientosFiltrados.add(unAsiento);
			}
		}
		return asientosFiltrados;
	}

	// cuando se implemente lo de escalas y busquedas
	// lo que se compra o reserva es un paquete de vuelos (varias escalas o varios asientos)
	public AterrizarPuntoCom unUsuarioCompraUnAsiento(Usuario unUsuario, Vuelo unAsiento) {
		// al no iterar mas, el try catch ya no es necesario porque relanzaba una excepcion
		// cuando trabajemos con escalas, voy a intentar los 2 asientos
		// si el segundo falla, tengo que borrar la primera reserva
		
		
		
		//unAsiento.comprar(unUsuario);
		unAsiento.comprar(Usuario.getInstance());
		Usuario.getInstance().getAsientosComprados().add(unAsiento);
	
		
		// TODO: revisar este cast, en el futuro se deber�a poder reservar vuelos (BRUNO Y NICO).
    	this.reservas.borrarReserva((Asiento)unAsiento);
    	return this;
	}
	
	// cuando se implemente lo de escalas y busquedas
	// lo que se compra o reserva es un paquete de vuelos (varias escalas o varios asientos)
	public void reservar(Vuelo vuelo, Usuario unUsuario)
	{
		// cuando trabajemos con escalas, voy a intentar los 2 asientos
		// si el segundo falla, tengo que borrar la primera reserva
		reservas.reservar(unUsuario, vuelo);
	}

	public void sobrereservar(Vuelo vuelo, Usuario unUsuario) {
		// cuando trabajemos con escalas, voy a intentar los 2 asientos
		// si el segundo falla, tengo que borrar la primera reserva
		reservas.sobrereservar(unUsuario, vuelo);
	}
}